package com.hup.minicontroller.server.service;

import android.os.Build;
import android.util.Log;

import com.hup.minicontroller.common.constant.NetConstant.ConnectType;
import com.hup.minicontroller.common.framework.MainThreadHandler;
import com.hup.minicontroller.common.model.dto.LoginRequest;
import com.hup.minicontroller.common.model.dto.LoginResponse;
import com.hup.minicontroller.common.netty.NettyTCPServer;
import com.hup.minicontroller.common.netty.NettyTCPServer.ServerCallback;
import com.hup.minicontroller.common.netty.NettyTCPServer.ServerConfig;
import com.hup.minicontroller.common.netty.NettyTCPServer.StartState;
import com.hup.minicontroller.common.netty.handler.DataCodecHandler;
import com.hup.minicontroller.common.netty.handler.HeartbeatHandler.IdleCallback;
import com.hup.minicontroller.common.netty.handler.LoginHandler;
import com.hup.minicontroller.common.netty.handler.dataListener.NetSpeedListener;
import com.hup.minicontroller.common.util.Assert;
import com.hup.minicontroller.server.R;
import com.hup.minicontroller.server.ServerApplication;
import com.hup.minicontroller.server.model.AppState;
import com.hup.minicontroller.server.model.OnlineClientSession;
import com.hup.minicontroller.server.mvp.ICursorFloaterView;
import com.hup.minicontroller.server.mvp.IMainView;
import com.hup.minicontroller.server.mvp.IScreenImageService;
import com.hup.minicontroller.server.mvp.IServerHandler;

import java.net.SocketAddress;
import java.util.Iterator;
import java.util.Locale;

import io.netty.channel.Channel;
import lombok.Getter;

/**
 * (wifi和热点)局域网server
 */
public class LanServerService implements IServerHandler {
    private static final String TAG = LanServerService.class.getSimpleName();

    private final AppState appState;
    private final ServerConfig serverConfig;
    private final NettyTCPServer server;
    private final NetSpeedListener netSpeedListener;

    @Getter
    private ConnectType connectType = ConnectType.LAN;

    LanServerService(AppState appState, DataRequestService dataRequestService) {
        this.appState = appState;
        MyServerCallback serverCallback = new MyServerCallback();
        serverConfig = new ServerConfig(0, serverCallback);
        serverConfig.bindRetryTime(0)//绑定失败时,不递增端口号
                .loginHandler(serverCallback)
                .setAddHeartbeat(true, new IdleCallback() {
                })
                .addDataHandler(dataRequestService);
        server = new NettyTCPServer(serverConfig);
        netSpeedListener = new NetSpeedListener();
        DataCodecHandler.INSTANCE.addDataListener(netSpeedListener);
    }

    @Override
    public void switchServer(boolean isStart) {
        Log.i(TAG, "switchServer: " + isStart);
        if (isStart) {
            //此处可以加入自动开启wifi和热点的业务
            serverConfig.port(appState.getAppConfig().getLanServerPort());
            server.startServer();
        } else {
            server.stopServer();
        }
    }

    @Override
    public void doTerminate() {
        Log.i(TAG, "doTerminate: ");
        if (StartState.STARTED.equals(server.getStartState())) {
            server.stopServer();
        }
    }

    @Override
    public void getSpeedText(StringBuilder sb) {
        if (server.getStartState() != StartState.STARTED) return;
        netSpeedListener.updateSpeed();
        sb.append(String.format(Locale.getDefault(), "局域网  发送: %dKB/s, 接收: %dKB/s", netSpeedListener.getSendSpeed(), netSpeedListener.getReceiveSpeed()));
    }


    /**
     * 处理服务端生命周期,客户端生命周期等消息
     */
    private class MyServerCallback extends LoginHandler<LoginRequest, LoginResponse> implements ServerCallback {

        @Override
        public void onServerStartResult(boolean success, Integer boundPort) {
            Log.i(TAG, "onServerStartResult: " + success + ", boundPort=" + boundPort);
            appState.setStartedLan(success);
            ServerApplication.executeIfExist(IMainView.class, i -> i.onNetServerStateChanged(getConnectType()));
            if (success) ServerApplication.executeIfExist(LanBroadcastSenderService.class, s -> s.switchService(true));
        }

        @Override
        public void onServerStopped() {
            Log.i(TAG, "onServerStopped: ");
            appState.setStartedLan(false);
            appState.accessClient(clientSessions -> clientSessions.removeIf(session -> session.getConnectType() == ConnectType.LAN));
            ServerApplication.executeIfExist(IMainView.class, i -> i.onNetServerStateChanged(getConnectType()));
            if (!MainService.SWITCH_SCREEN_ON_BOOT) {
                ServerApplication.executeIfExist(IScreenImageService.class, i -> i.switchService(appState.hasClient()));
            }
        }

        @Override
        protected Class<LoginRequest> getLoginRequestType() {
            return LoginRequest.class;
        }

        @Override
        protected void doLoginValid(SocketAddress address, LoginRequest data) throws LoginException {
            Log.i(TAG, "doLoginValid: 按需校验认证" + data);
            try {
                Assert.hasText(data.getName(), () -> "用户名为空");
//                throw new IllegalAccessException("测试认证不通过");
            } catch (Exception e) {
                throw new LoginException(e.getMessage());
            }
        }

        @Override
        protected LoginResponse getLoginSuccessResponse(Channel channel, LoginRequest loginReq) {
            Log.i(TAG, "getLoginSuccessResponse: 按需设计回复数据");
            return new LoginResponse(Build.MODEL, appState.getControlConfig().toDto());
        }

        @Override
        public void onClientConnectChanged(boolean onLine, Channel channel) {
            appState.accessClient(onlineClientSessions -> {
                Log.i(TAG, "onClientConnectChanged: onLine=" + onLine + ", channel=" + channel);
                if (onLine) {
                    LoginRequest loginRequest = getLoginRequestData(channel);
                    OnlineClientSession session = OnlineClientSession.lan(loginRequest, channel);
                    onlineClientSessions.add(session);
                    ServerApplication.getBean(MainThreadHandler.class).post(() ->
                            ServerApplication.executeIfExist(ICursorFloaterView.class, ICursorFloaterView::onClientOnline));
                } else {
                    if (StartState.STOPPED.equals(server.getStartState())) {
                        Log.i(TAG, "onClientConnectChanged: server关闭后,客户端下线事件");
                        //由onServerStopped更新session并通知ui
                        return;
                    }
                    Iterator<OnlineClientSession> it = onlineClientSessions.iterator();
                    while (it.hasNext()) {
                        if (channel.equals(it.next().getChannel())) {
                            it.remove();
                            break;
                        }
                    }
                }
                ServerApplication.executeIfExist(SoundService.class, s -> s.play(onLine ? R.raw.online : R.raw.offline));
                ServerApplication.executeIfExist(IMainView.class, IMainView::onClientChanged);
                if (!MainService.SWITCH_SCREEN_ON_BOOT) {
                    ServerApplication.executeIfExist(IScreenImageService.class, i -> i.switchService(appState.hasClient()));
                }
            });
        }
    }

}
